// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/screen_orientation/screen_orientation_delegate_win.h"

#include <windows.h>

#include "content/public/browser/screen_orientation_provider.h"

namespace {

// SetDisplayAutoRotationPreferences is available on Windows 8 and after.
void SetDisplayAutoRotationPreferencesWrapper(
    ORIENTATION_PREFERENCE orientation)
{
    using SetDisplayAutoRotationPreferencesPtr = void(WINAPI*)(ORIENTATION_PREFERENCE);
    static SetDisplayAutoRotationPreferencesPtr
        set_display_auto_rotation_preferences_func
        = reinterpret_cast<SetDisplayAutoRotationPreferencesPtr>(
            GetProcAddress(GetModuleHandleA("user32.dll"),
                "SetDisplayAutoRotationPreferences"));
    if (set_display_auto_rotation_preferences_func)
        set_display_auto_rotation_preferences_func(orientation);
}

// GetAutoRotationState is available on Windows 8 and after.
BOOL GetAutoRotationStateWrapper(PAR_STATE state)
{
    using GetAutoRotationStatePtr = BOOL(WINAPI*)(PAR_STATE);
    static GetAutoRotationStatePtr get_auto_rotation_state_func = reinterpret_cast<GetAutoRotationStatePtr>(GetProcAddress(
        GetModuleHandleA("user32.dll"), "GetAutoRotationState"));
    if (get_auto_rotation_state_func)
        return get_auto_rotation_state_func(state);
    return FALSE;
}

bool GetDisplayOrientation(bool* landscape, bool* flipped)
{
    DEVMODE dm = {};
    dm.dmSize = sizeof(dm);
    if (!EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &dm))
        return false;
    *flipped = (dm.dmDisplayOrientation == DMDO_270 || dm.dmDisplayOrientation == DMDO_180);
    *landscape = (dm.dmPelsWidth > dm.dmPelsHeight);
    return true;
}

} // namespace

namespace content {

ScreenOrientationDelegateWin::ScreenOrientationDelegateWin()
{
    ScreenOrientationProvider::SetDelegate(this);
}

ScreenOrientationDelegateWin::~ScreenOrientationDelegateWin()
{
    ScreenOrientationProvider::SetDelegate(nullptr);
}

bool ScreenOrientationDelegateWin::FullScreenRequired(
    WebContents* web_contents)
{
    return false;
}

void ScreenOrientationDelegateWin::Lock(
    WebContents* web_contents,
    blink::WebScreenOrientationLockType lock_orientation)
{
    ORIENTATION_PREFERENCE prefs = ORIENTATION_PREFERENCE_NONE;
    bool landscape = true;
    bool flipped = false;
    switch (lock_orientation) {
    case blink::WebScreenOrientationLockPortraitPrimary:
        prefs = ORIENTATION_PREFERENCE_PORTRAIT;
        break;
    case blink::WebScreenOrientationLockPortraitSecondary:
        prefs = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
        break;
    case blink::WebScreenOrientationLockLandscapePrimary:
        prefs = ORIENTATION_PREFERENCE_LANDSCAPE;
        break;
    case blink::WebScreenOrientationLockLandscapeSecondary:
        prefs = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
        break;
    case blink::WebScreenOrientationLockPortrait:
        if (!GetDisplayOrientation(&landscape, &flipped))
            return;
        prefs = (flipped && !landscape) ? ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED
                                        : ORIENTATION_PREFERENCE_PORTRAIT;
        break;
    case blink::WebScreenOrientationLockLandscape:
        if (!GetDisplayOrientation(&landscape, &flipped))
            return;
        prefs = (flipped && landscape) ? ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED
                                       : ORIENTATION_PREFERENCE_LANDSCAPE;
        break;
    case blink::WebScreenOrientationLockNatural:
        if (!GetDisplayOrientation(&landscape, &flipped))
            return;
        prefs = landscape ? ORIENTATION_PREFERENCE_LANDSCAPE
                          : ORIENTATION_PREFERENCE_PORTRAIT;
        break;
    case blink::WebScreenOrientationLockAny:
        if (!GetDisplayOrientation(&landscape, &flipped))
            return;
        if (landscape) {
            prefs = flipped ? ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED
                            : ORIENTATION_PREFERENCE_LANDSCAPE;
        } else {
            prefs = flipped ? ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED
                            : ORIENTATION_PREFERENCE_PORTRAIT;
        }
        break;
    case blink::WebScreenOrientationLockDefault:
    default:
        break;
    }
    SetDisplayAutoRotationPreferencesWrapper(prefs);
}

bool ScreenOrientationDelegateWin::ScreenOrientationProviderSupported()
{
    AR_STATE auto_rotation_state = {};
    return (GetAutoRotationStateWrapper(&auto_rotation_state) && !(auto_rotation_state & AR_NOSENSOR) && !(auto_rotation_state & AR_NOT_SUPPORTED) && !(auto_rotation_state & AR_MULTIMON));
}

void ScreenOrientationDelegateWin::Unlock(WebContents* web_contents)
{
    SetDisplayAutoRotationPreferencesWrapper(ORIENTATION_PREFERENCE_NONE);
}

} // namespace content
